package com.chancein.cloud.ocr.process.api.impl;

import com.alibaba.fastjson.JSONObject;
import com.chancein.cloud.ocr.process.OcrProcessApiService;
import com.chancein.cloud.ocr.process.domain.OcrExcelData;
import com.chancein.cloud.ocr.process.domain.dto.OcrClassifyDto;
import com.chancein.cloud.ocr.process.util.FileUtils;
import com.chancein.cloud.ocr.process.util.HsOcrUtils;
import com.chancein.cloud.ocr.process.util.OcrUtils;
import com.chancein.cloud.ocr.process.util.ParseHostUtils;
import com.chancein.cloud.report.charts.domain.OcrProcessReqDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;

import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.ConnectException;
import java.net.URL;
import java.util.concurrent.atomic.AtomicReference;

/**
 * ocr 处理服务实现类
 *
 * @author: LiaoZiHao
 * @date: 2023/8/8 18:00
 * Copyright © 2022 Hundsun Technologies Inc. All Rights Reserved
 */
@Slf4j
public class OcrProcessApiServiceImpl implements OcrProcessApiService {
    /**
     * 魔法值http
     */
    public static final String MAGIC_VALUE_HTTP = "http";

    @Override
    public OcrExcelData getExcel(OcrProcessReqDto reqDto) {
        InputStream inputStream = null;
        ByteArrayOutputStream bs = null;
        ImageOutputStream imOut = null;
        try {
            String url = reqDto.getUri();
            // 处理相对路径
            if (!url.startsWith(MAGIC_VALUE_HTTP)) {
                url = reqDto.getOrigin() + url;
            }
            // 如果 reqDto.getOrigin() 为 ""，则使用默认的路径相连得到完整的 url 路径
            url = ParseHostUtils.getFullUrl(url);
            URL httpUrl = new URL(url);
            // 用于存储读取到的图片数据
            BufferedImage img;
            try {
                // 读取 httpUrl 来获取图片数据
                img = ImageIO.read(httpUrl);
            } catch (IIOException e) {
                log.error("[OCR]未找到此文件; 错误数据[id=" + fetchReportChartsId(reqDto.getChartJson()) + "]未找到此文件");
                log.error("[OCR]httpUrl=" + httpUrl);
                return null;
            }
            // 用于将图片数据写入字节数组流
            bs = new ByteArrayOutputStream();
            // 创建一个 ImageOutputStream 对象，与字节数组流相关联，用于将图片数据写入字节数组流。
            imOut = ImageIO.createImageOutputStream(bs);
            // 得到文件 url 的后缀
            String suffixStr = FileUtils.getNetworkFileExt(url);
            if (StringUtils.isBlank(suffixStr)) {
                suffixStr = "png";
            }
            AtomicReference<String> suffix = new AtomicReference<>();
            suffix.set(suffixStr);

            if (img == null) {
                return null;
            }
            // 将读取到的图片数据以指定格式（后缀名）写入到字节数组流中
            ImageIO.write(img, suffix.get(), imOut);
            // TODO 将字节数组流转化为 inputStream，作为最终地返回结果
            byte[] bytes = bs.toByteArray();
            inputStream = new ByteArrayInputStream(bytes);

            OcrExcelData data = null;
            // 判断是否使用自有矢量图方试进行解析
            if (StringUtils.isNotBlank(HsOcrUtils.getPicOcrUrl())) {
                if (StringUtils.isNotBlank(reqDto.getChartJson())) {
                    JSONObject jsonObject = JSONObject.parseObject(reqDto.getChartJson());
                    String ipadMarkerType = jsonObject.getString("ipadMarkerType");

                    String vectorgraphText = reqDto.getVectorgraphText();
                    String chartPos = jsonObject.getString("picRect");
                    Integer pageIndex = null;
                    String filePath = "";
                    String fileName = "";

                    boolean enablePic = false;
                    if ("搜索云盘图表".equals(ipadMarkerType)) {
                        String tmpPath = jsonObject.getString("filePath");
                        if (StringUtils.isNotBlank(tmpPath) && tmpPath.startsWith(MAGIC_VALUE_HTTP)) {
                            filePath = tmpPath;
                        } else {
                            filePath = reqDto.getOrigin() + jsonObject.getString("filePath");
                        }
                        fileName = jsonObject.getString("sourceFileId");
                        pageIndex = jsonObject.getInteger("elementIndex");
                        enablePic = true;
                    } else if ("搜索研报图表".equals(ipadMarkerType)) {
                        String tmpPath = jsonObject.getString("pdfFilePath");
                        if (StringUtils.isNotBlank(tmpPath) && tmpPath.startsWith(MAGIC_VALUE_HTTP)) {
                            filePath = tmpPath;
                        } else {
                            filePath = reqDto.getOrigin() + jsonObject.getString("pdfFilePath");
                        }
                        fileName = jsonObject.getString("id");
                        pageIndex = jsonObject.getInteger("pageIndex");
                        if (pageIndex != null) {
                            pageIndex --;
                        }
                        enablePic = true;
                    }
                    if (enablePic && StringUtils.isNotBlank(vectorgraphText) && StringUtils.isNotBlank(chartPos)) {
                        String jsonStr = HsOcrUtils.getPicData(filePath, fileName, pageIndex, vectorgraphText, chartPos);
                        try {
                            data = HsOcrUtils.getExcelData(jsonStr);
                        } catch (IndexOutOfBoundsException e) {
                            log.error("[OCR]数组越界; 错误数据[id=" + fetchReportChartsId(reqDto.getChartJson()) + "]数组越界");
                            return null;
                        }
                    }
                }
            }
            // 判断是否配置了恒生ocr
            if (data == null && StringUtils.isNotBlank(HsOcrUtils.getHsOcrUrl())) {
                // OcrClassifyDto ocrClassifyDto = this.hsChartClassify(reqDto.getOrigin(), reqDto.getUri(), reqDto.getTimestamp());
                ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
                OcrClassifyDto ocrClassifyDto = this.hsChartClassify2(stream, suffix);
                if (ocrClassifyDto != null && ocrClassifyDto.getOkFlag()) {
                    String jsonStr = HsOcrUtils.imageAnalyticalStreamV2(inputStream, suffix.get(), reqDto.getVectorgraphText());
                    try {
                        data = HsOcrUtils.getExcelData(jsonStr);
                    } catch (IndexOutOfBoundsException e) {
                        log.error("[OCR]数组越界; 错误数据[id=" + fetchReportChartsId(reqDto.getChartJson()) + "]数组越界");
                        return null;
                    }
                }
            }
            // 百度 ocr
//            if (data == null) {
//                inputStream = new ByteArrayInputStream(bs.toByteArray());
//                String jsonStr = OcrUtils.imageAnalyticalStream(inputStream);
//                data = OcrUtils.getExcelData(jsonStr);
//            }
            return data;
        } catch (ConnectException e) {
            log.error("[OCR]拒绝连接; 错误数据[id=" + fetchReportChartsId(reqDto.getChartJson()) + "]拒绝连接");
            log.error("[System]系统停止运行...");
            System.exit(0);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (bs != null) {
                try {
                    bs.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (imOut != null) {
                try {
                    imOut.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        return null;
    }

    public OcrClassifyDto hsChartClassify(String origin, String uri, Long timestamp) {
        OcrClassifyDto result = new OcrClassifyDto();
        try {
            AtomicReference<String> suffix = new AtomicReference<>();
            InputStream inputStream = this.getInputStream(origin, uri, suffix);
            Assert.notNull(inputStream, "无法解析路径");
            result = HsOcrUtils.hsChartClassify(inputStream, suffix.get());
        } catch (Exception e) {
            log.error("OcrProcessApiServiceImpl.checkHsClassify【error】->", e);
            result.setOkFlag(false);
            result.setErrMsg("解析对象异常");
        }
        return result;
    }

    public OcrClassifyDto hsChartClassify2(InputStream inputStream, AtomicReference<String> suffix) {
        OcrClassifyDto result = new OcrClassifyDto();
        try {
            result = HsOcrUtils.hsChartClassify(inputStream, suffix.get());
        } catch (Exception e) {
            log.error("OcrProcessApiServiceImpl.checkHsClassify【error】->", e);
            result.setOkFlag(false);
            result.setErrMsg("解析对象异常");
        }
        return result;
    }

    private InputStream getInputStream(String origin, String uri, AtomicReference<String> suffix) {
        InputStream inputStream = null;
        ByteArrayOutputStream bs = null;
        ImageOutputStream imOut = null;
        try {
            String url = uri;
            if (!uri.startsWith(MAGIC_VALUE_HTTP)) {
                url = origin + uri;
            }
            URL httpUrl = new URL(url);
            BufferedImage img = ImageIO.read(httpUrl);
            bs = new ByteArrayOutputStream();
            imOut = ImageIO.createImageOutputStream(bs);
            String suffixStr = FileUtils.getNetworkFileExt(url);
            if (StringUtils.isBlank(suffixStr)) {
                suffixStr = "png";
            }
            suffix.set(suffixStr);
            ImageIO.write(img, suffix.get(), imOut);
            inputStream = new ByteArrayInputStream(bs.toByteArray());
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (bs != null) {
                try {
                    bs.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (imOut != null) {
                try {
                    imOut.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        return inputStream;
    }

    public static String fetchReportChartsId(String chartJson) {
        JSONObject chartJsonObj = JSONObject.parseObject(chartJson);
        return chartJsonObj.getString("id");
    }
}
